package net.lovesrc.support.service.generator.bankcard;

import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author clg
 * Created at 16:01 2018/11/30
 * @since 1.1
 */
public class BankCardBinGenerate {

    private static final Logger logger = LoggerFactory.getLogger(BankCardBinGenerate.class);

    private static final Random random = new Random(System.currentTimeMillis());

    private BankCardBinGenerate() {
    }

    private static List<BankCardBin> bankCardBins = new ArrayList<>();

    static {
        doInit();
    }

    public static void doInit() {
        try {
            InputStream is = BankCardBinGenerate.class.getResourceAsStream("/bank_bin.csv");
            Stream<String> lines = new BufferedReader(new InputStreamReader(is, "utf-8")).lines();
            lines.filter(line -> !StringUtils.isBlank(line))
                    .forEach(line -> {
                        String[] arr = line.split(",");
                        if (arr == null || arr.length != 5) {
                            return;
                        }
                        BankCardTypeEnum bankCardTypeEnum = BankCardTypeEnum.parseBySname(arr[3]);
                        int length = NumberUtils.isParsable(arr[4]) ? Integer.parseInt(arr[4]) : 18;
                        BankCardBin bankCardBin = new BankCardBin(arr[0], arr[1], arr[2], bankCardTypeEnum, length);
                        bankCardBins.add(bankCardBin);
                    });
            if (bankCardBins.isEmpty()) {
                throw new RuntimeException("初始化银行卡失败");
            }
            System.out.println("加载了" + bankCardBins.size() + "条银行卡bin信息");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static BankCardBin generate() {
        return bankCardBins.get(random.nextInt(bankCardBins.size()));
    }

    /**
     * 根据银行名称 及银行卡类型生成对应卡号
     *
     * @param bankName 银行名称
     * @param cardType 银行卡类型
     * @return 银行卡号
     */
    public static BankCardBin generate(BankNameEnum bankName, BankCardTypeEnum cardType) {
        Integer[] candidatePrefixes = null;
        if (cardType == null) {
            candidatePrefixes = bankName.getAllCardPrefixes();
        } else {
            switch (cardType) {
                case DEBIT:
                    candidatePrefixes = bankName.getDebitCardPrefixes();
                    break;
                case CREDIT:
                    candidatePrefixes = bankName.getCreditCardPrefixes();
                    break;
                default:
            }
        }
        if (candidatePrefixes != null && candidatePrefixes.length > 0) {
            Integer prefix = candidatePrefixes[random.nextInt(candidatePrefixes.length)];
            return new BankCardBin(prefix.toString(), "", bankName.getName(), cardType, 18);
        }

        if (!bankCardBins.isEmpty()) {
            List<BankCardBin> bankCardBinList = bankCardBins.stream()
                    .filter(bankCardBin -> {
                        if (bankCardBin.bankCardTypeEnum == null) {
                            return false;
                        }
                        if (bankCardBin.bankCardTypeEnum.equals(cardType)
                                && bankCardBin.getTitle().equals(bankName.getName())) {
                            return true;
                        }
                        return false;
                    })
                    .collect(Collectors.toList());

            if (bankCardBinList != null && !bankCardBinList.isEmpty()) {
                return bankCardBinList.get(random.nextInt(bankCardBinList.size()));
            }
        }
        throw new RuntimeException("没有" + bankName + "银行的" + cardType + "的卡号信息");
    }

    @Data
    public static class BankCardBin {
        private String cardbin;
        private String sname;
        private String title;
        private BankCardTypeEnum bankCardTypeEnum;
        private int length = 18;

        public BankCardBin() {
        }

        public BankCardBin(String cardbin, String sname, String title, BankCardTypeEnum bankCardTypeEnum, int length) {
            this.cardbin = cardbin;
            this.sname = sname;
            this.title = title;
            this.bankCardTypeEnum = bankCardTypeEnum;
            this.length = length;
        }

        public String getCardbin() {
            return cardbin;
        }

        public void setCardbin(String cardbin) {
            this.cardbin = cardbin;
        }

        public String getSname() {
            return sname;
        }

        public void setSname(String sname) {
            this.sname = sname;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public BankCardTypeEnum getBankCardTypeEnum() {
            return bankCardTypeEnum;
        }

        public void setBankCardTypeEnum(BankCardTypeEnum bankCardTypeEnum) {
            this.bankCardTypeEnum = bankCardTypeEnum;
        }

        public int getLength() {
            return length;
        }

        public void setLength(int length) {
            this.length = length;
        }
    }

}
